/**
 * Copyright (c) 2023 Yin. All rights reserved.
*/

#ifndef _AES_H
#define _AES_H
#include "padding.h"
//对加密后的内容使用base64编码
#define AES_BASE64_ENCODE
 
//加密类型对应的密匙长度，单位bit
typedef enum {
    AES128 = 128,
    AES192 = 192,
    AES256 = 256,
} AESType_t;
 
//加解密模式
typedef enum {
    AES_MODE_ECB = 0,   // 电子密码本模式
    AES_MODE_CBC = 1,   // 密码块连接模式
    AES_MODE_CFB = 2,   // 密文反馈模式 
    AES_MODE_OFB = 3,   // 输出反馈模式 
    AES_MODE_CTR = 4,   // 计数器模式   
} AESMode_t;

//块大小
#define Nb    4     //加解密数据块大小，固定为4，AES固定块大小为128bit

typedef struct {
    int Nk;         //用户不需要填充，密钥长度，单位字节, AES128:Nk=16、AES192:Nk=24、AES256:Nr=32
    int Nr;         //用户不需要填充，加密的轮数 AES128:Nr=10、AES192:Nr=12、AES256:Nr=14
    int type;       //用户需填充，关联AESType_t
    int mode;       //用户需填充，关联AESMode_t
    int padding;    //用户需填充，关联AESPadding_t
    unsigned char key[8*Nb];//初始化时填入，密匙
    unsigned char pIV[4*Nb];//初始化时填入，初始化向量
                    //只有当 mode=AES_MODE_EBC 时不需要设置，其他都需要
                    //当 mode=AES_MODE_CTR 时，其值含义为 Nonce + counter 的初始值
    unsigned char expandKey[4*Nb*(14+1)];       //用户不需要填充，[4*Nb*(Nr+1)]、这里按最大的AES256进行初始化
                                                //AES拓展密匙, 空间大小 AES128:4*Nb*(10+1):4*Nb*(12+1)、AES256:4*Nb*(14+1)
    void (*ctr_alg)(void *Nonce, int counter);  //mode=AES_MODE_CTR 时需要填充，需要自行实现计数器的算法。
                                                //其中第一个参数系统中默认将pIV的内容传入。第二个参数为轮次counter = 0,1,2...
                                                //输出结果存放到Nonce指向的空间。（修改Nonce并不会改变结构体中pIV的值）
} AESInfo_t; 
 

/**
 * @brief get the size that encrypt data size requires
 * @param s before encrypt data length
 * @return back to the size that encrypt data need
 * @note it always used to get the size that CipherText before you encrypt data,
 *       it make sure that CipherText would not out of memory
 */
#ifdef AES_BASE64_ENCODE
#define getEncodeRequireSize(s) (((((s)>>4)+1<<4)+2)*4/3)
// (n+2)*4/3 如加密前4字节,aes加密后变成16字节,base64编码后则需要24字节的空间
#else
#define getEncodeRequireSize(s) (((s)>>4)+1<<4)
#endif


/**
 * @brief aes init function
 * 
 * @param aesInfoP aes info block. user need to set type,mode,padding,ctr_alg separately
 * @param key crypt key if type=AES128 only 16 byte is used, AES192 for 24bytes , AES256 for 32bytes
 * @param pIV vector value, it makes aes more safer
 * @note the pointer to key space requires 32 bytes, the pointer to pIV space requires 16 bytes.
 */
void AESInit(AESInfo_t *aesInfoP, unsigned char *key, unsigned char *pIV);
 

/**
 * @brief aes Encrypt
 * 
 * @param aesInfoP aes info block
 * @param pPlainText before Encrypt data
 * @param pCipherText after Encrypt data
 * @param dataLen before Encrypt data length
 * @return unsigned int after Encrypt data length
 */
unsigned int AESEncrypt(AESInfo_t *aesInfoP, const unsigned char *pPlainText, unsigned char *pCipherText, unsigned int dataLen);
 
/**
 * @brief aes Decrypt
 * 
 * @param aesInfoP aes info block
 * @param pPlainText after Decrypt data
 * @param pCipherText before Decrypt data
 * @param nDataLen before Decrypt data length
 * @return unsigned int after Decrypt data length
 */
unsigned int AESDecrypt(AESInfo_t *aesInfoP, unsigned char *pPlainText, const unsigned char *pCipherText, unsigned int nDataLen);
 
#endif  /* _AES_H */

